package com.youxin.admin.auth.service.Impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youxin.admin.auth.domain.ChatUserDto;
import com.youxin.admin.auth.domain.router.VueRouter;
import com.youxin.admin.auth.mapper.ChatLoginLogMapper;
import com.youxin.admin.auth.mapper.MenuMapper;
import com.youxin.admin.auth.mapper.UserMapper;
import com.youxin.admin.auth.model.LoginLog;
import com.youxin.admin.auth.model.User;
import com.youxin.admin.auth.model.UserDto;
import com.youxin.admin.auth.service.ChatMenuService;
import com.youxin.admin.auth.service.ChatUserService;
import com.youxin.admin.auth.service.PermissionService;
import com.youxin.admin.auth.service.ValidateCodeService;
import com.youxin.base.BaseResultCode;
import com.youxin.base.TPage;
import com.youxin.base.TResult;
import com.youxin.common.constant.RedisKey;
import com.youxin.exception.SystemException;
import com.youxin.utils.IPUtil;
import com.youxin.utils.MD5Util;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class ChatUserServiceImpl extends ServiceImpl<UserMapper, User> implements ChatUserService {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private UserMapper userMapper;

    @Resource
    private ChatLoginLogMapper chatLoginLogMapper;


    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private ChatMenuService chatMenuService;

    @Resource
    private ValidateCodeService validateCodeService;

    @Resource
    private PermissionService permissionService;

    @Override
    public User getUserByUsername(String username) throws SystemException {
        User user = this.baseMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
        return user;
    }

    @Override
    public boolean insert(User user) throws SystemException {
        user.setPassword(MD5Util.md5Salt(user.getPassword(), user.getUsername(), 1));
        User param = new User();
        param.setUsername(user.getUsername());
        if (this.baseMapper.selectCount(new QueryWrapper<User>(param)) > 0) {
            throw new SystemException("10001", "用户已存在");
        }
        return this.baseMapper.insert(user) > 0;
    }

    @Override
    public User selectById(Integer id) throws SystemException {
        return this.baseMapper.selectById(id);
    }

    @Override
    public boolean deleteById(Integer id) throws SystemException {
       return this.baseMapper.deleteById(id) > 0;
    }

    @Override
    public boolean updateById(User user) throws SystemException {
        return this.baseMapper.updateById(user) > 0;
    }

    @Override
    public IPage<User> selectByPage(IPage<User> page, QueryWrapper<User> entityWrapper) throws SystemException {
        return this.baseMapper.selectPage(page, entityWrapper);
    }

    @Override
    public List<User> selectList(QueryWrapper<User> entityWrapper) throws SystemException {
        return this.baseMapper.selectList(entityWrapper);
    }

    @Override
    public void updateLoginTime(String username) throws SystemException {
        User user = new User();
        user.setLastLoginTime(new Date());
        this.baseMapper.update(user, new QueryWrapper<User>().eq("username", username));
    }

    @Override
    public TPage<List<ChatUserDto>> selectChatUserList(ChatUserDto chatUserDto, int currentPage, int showCount) throws SystemException {
        IPage page = this.baseMapper.selectChatUserList(chatUserDto, new Page<>(currentPage, showCount));
        return TPage.page(page.getRecords(), page.getTotal());
    }

    @Override
    public TResult<UserDto> login(String username, String password, String merchantNo, String validateCode, String key, HttpServletRequest request) throws SystemException {
        try {
            if (!validateCodeService.check(key,validateCode)) {
                logger.error("验证码不正确，code={},validateCode={}", validateCode, validateCode);
                return TResult.build(BaseResultCode.COMMON_FAIL, "验证码不正确");
            }
            User user = getUserByUsername(username);
            password = MD5Util.md5Salt(password, username, 1);
            if (user == null) {
                logger.error("用户不存在，username={},merchantNo={}", username, merchantNo);
                return TResult.build(BaseResultCode.COMMON_FAIL, "用户不存在");
            }
            if (!StringUtils.equals(user.getPassword(), password)) {
                logger.error("用户密码错误，username={},merchantNo={}", username, merchantNo);
                return TResult.build(BaseResultCode.COMMON_FAIL, "用户密码错误");
            }
            if ("0".equalsIgnoreCase(user.getStatus())) {
                logger.error("账号已被锁定,请联系管理员，username={},merchantNo={}", username, merchantNo);
                return TResult.build(BaseResultCode.COMMON_FAIL, "账号已被锁定,请联系管理员");
            }


            user.setPassword("No comment");
            // 更新用户登录时间
            this.baseMapper.updateLoginTime(username);
            String token = MD5Util.MD5(UUID.randomUUID().toString());

            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            request = servletRequestAttributes.getRequest();
            LoginLog loginLog = new LoginLog();
            loginLog.setUserName(username);
            loginLog.setIp(IPUtil.getIpAddr(request));
            loginLog.setLoginTime(LocalDateTime.now());
            chatLoginLogMapper.insert(loginLog);

            UserDto userDto = new UserDto();
            userDto.setId(user.getId());
            userDto.setUsername(user.getUsername());
            userDto.setName(user.getName());
            userDto.setSex(user.getSex());
            userDto.setDescription(user.getDescription());
            userDto.setMobilePhone(user.getMobilePhone());
            userDto.setEmail(user.getEmail());
            userDto.setLastLoginTime(user.getLastLoginTime());
            userDto.setToken(token);
            Set<String>  permissionSet = permissionService.getPermissionByUsername(username);
            String permissions = StringUtils.join(permissionSet,",");
            userDto.setPermissions(permissions);
            stringRedisTemplate.opsForValue().set(RedisKey.ADMIN_USER_INFO + token, JSONObject.toJSONString(userDto),1,TimeUnit.HOURS);
            return TResult.success(userDto);

        } catch (Exception e) {
            logger.error("用户登录异常，username={},merchantNo={}", username, merchantNo, e);
            return TResult.build(BaseResultCode.COMMON_FAIL, "系统异常，请联系技术人员");
        }
    }

    @Override
    public TResult<Map<String, Object>> info(String userName) throws SystemException {
        Map<String, Object> map = new HashMap<>();
        TResult<Set<String>> permissionsResult = chatMenuService.getPermissionsByUserName(userName);
        TResult<List<VueRouter>> routersResult = chatMenuService.getRouterByUser(userName);
        Set<String> permissions = Optional.ofNullable(permissionsResult).map(TResult::getData).orElse(new HashSet<>());
        List<VueRouter> routers = Optional.ofNullable(routersResult).map(TResult::getData).orElse(new ArrayList<>());
        User user = getUserByUsername(userName);
        user.setPassword("****");
        user.setAuthKey(null);
        map.put("permissions", permissions);
        map.put("routers", routers);
        map.put("user", user);
        return TResult.success(map);
    }

}
